<template>
  <div>
    <el-row
      :id="'Common' + tabs"
      :ref="'Common' + tabs"
      :gutter="20"
      :class="isMore ? 'common-filter-container-wrap-more' : 'common-filter-container-wrap'"
    >
      <div class="common-filter-container-div">
        <el-form :ref="'FormRef' + tabs" size="small" :inline="true" :model="searchParam" class="demo-form-inline">
          <template v-for="item in formColumns">
            <el-form-item v-if="item.search" :key="item.prop" :label="`${item.label}:`">
              <SearchFormItem :column="item" :search-param="searchParam">
                <slot v-if="item.searchSlot" :name="item.searchSlot" :scope="searchParam" />
              </SearchFormItem>
            </el-form-item>
          </template>
        </el-form>
      </div>
      <div class="submit-container">
        <el-button :loading="submitLoading" class="btn-loading" size="medium" type="primary" @click="onSubmit('search')">查询</el-button>
        <el-button :loading="resetLoading" class="btn-loading" size="medium" @click="onSubmit('reset')">重置</el-button>
        <el-button
          v-if="showMoreButton"
          class="more-button"
          type="text"
          @click="isMore = !isMore"
        >
          {{ isMore ? '收起' : '展开' }}
          <i class="el-icon--right" :class="isMore ? 'el-icon-arrow-up' : 'el-icon-arrow-down'" />
        </el-button>
      </div>
    </el-row>
    <div :class="tableSpaceCss ? 'table-space' : ''" />
    <!--表格-->
    <div class="table-container" :style="{ paddingTop: !tableSpaceCss ? 0 : 16 }">
      <!--列设置按钮-->
      <div v-if="colSetting" class="col-container">
        <div class="col-slot">
          <slot name="btns" :row="{ selectList, tableData, searchParam }" />
        </div>
        <div v-if="columnsSetting && tableData.length > 0" class="operation-container">
          <el-dropdown trigger="hover">
            <!-- <i class="el-icon-setting" /> -->
            <i><svg-icon icon-class="setting" class-name="reset-svg" /></i>
            <!-- <el-button icon="el-icon-setting" size="mini" type="text" /> -->
            <el-dropdown-menu slot="dropdown" class="col-dropdown">
              <span class="title">列设置</span>
              <Tree
                ref="childrenTree"
                reset-sort
                :columns="columns"
              />
            </el-dropdown-menu>
          </el-dropdown>
          <screenfull
            v-if="columnsScreenfull"
            id="screenfull"
            :change="screenfullChange"
            dom="screenfull-table"
          />
        </div>
      </div>
      <el-table
        ref="table"
        :key="tableKey"
        v-loading="tableLoading"
        :max-height="mergeHeight"
        :data="tableData"
        border
        :row-style="{ height:40 , fontSize:14 }"
        :cell-style="{ padding: 0 }"
        :header-cell-style="{
          height: 46,
          fontSize: 14,
          lineHeight: 46,
          padding: 0,
          backgroundColor: '#f3f3f3',
          color: '#262626'
        }"
        size="mini"
        tooltip-effect="dark"
        v-bind="tableProps"
        @row-click="handelTableClick"
        @select="handleInitiativeSelect"
        @select-all="handleInitiativeAllSelect"
        @selection-change="handleSelectionChange"
      >
        <template slot="empty">
          <div description="暂无数据" />
        </template>
        <template v-for="item in columns">
          <template v-if="item.show && item.prop === 'selection'">
            <el-table-column :key="item.prop" fixed="left" :resizable="false" reserve-selection type="selection" />
          </template>
          <template v-else-if="item.show && item.prop === 'actions'">
            <!-- 固定列 -->
            <el-table-column
              :key="item.prop"
              class-name="actions"
              fixed="right"
              align="center"
              :label="item.label ? 'item.label' : '操作'"
              :width="item.width"
              v-bind="item.columnProps"
              :resizable="false"
            >
              <div slot-scope="scope" class="col-slot">
                <slot name="actions" :scope="{ ...scope }" />
              </div>
            </el-table-column>
          </template>
          <template v-else>
            <el-table-column
              v-if="item.show"
              :key="item.prop"
              align="left"
              show-overflow-tooltip
              :prop="item.prop"
              :sortable="!item.sortable"
              :label="item.label"
              :width="item.width"
              :resizable="true"
              :min-width="120"
              v-bind="item.columnProps"
            >
              <template slot="header" slot-scope="scope">
                <el-tooltip :content="item.label" placement="top">
                  <div :ref="'refName' + scope.$index" class="title title-header">
                    {{ item.label }}
                  </div>
                </el-tooltip>
                <!-- <el-popover placement="bottom" title="请选择" width="200" trigger="hover">
                  <div slot="reference" class="search-header">
                      <i class="search-icon el-icon-search"></i>
                  </div>
                  <div>单项搜索预留</div>
                </el-popover> -->
              </template>
              <template slot-scope="scope">
                <span v-if="item.slot">
                  <slot :name="item.slot" :scope="scope" />
                </span>
                <span v-else-if="item.type === 'time' && scope.row[item.prop]">{{
                  dayjs(scope.row[item.prop]).format('YYYY年MM月DD日')
                }}</span>
                <span v-else>{{ renderEnum(scope, item) }}</span>
              </template>
            </el-table-column>
          </template>
        </template>
      </el-table>
      <slot :scope="pageable" name="pagination">
        <Pagination
          v-if="pagination && tableData.length > 0 && pageShow"
          ref="pageRef"
          :tabs="activeName"
          :pageable="pageable"
          :handle-size-change="handleSizeChange"
          :handle-current-change="handleCurrentChange"
        />
      </slot>
    </div>
  </div>
</template>
<script>
import SearchFormItem from './search-form-item'
import Screenfull from '../Screenfull'
// import { mapState } from 'vuex'
import Tree from './tree'
import Pagination from './pagination'
import dayjs from 'dayjs'

/**
draggable
check-strictly
@node-drop="handleDrop"
:allow-drop="allowDrop"
 */

/**
columns 可以查看 element 组件库配置， 这里列出常用项
  prop: 'name', // 对应列内容的字段名
  label: '姓名', // 显示的标题
  width: 90, // 对应列的宽度
  resizable: true, // 对应列是否可以通过拖动改变宽度（需要在 el-table 上设置 border 属性为真） , 暂时启用， 父子组件传会报错
  hide: false, // 展示与隐藏 默认 false 不传
  sortable: true, // 对应列是否可以排序
  disabled: true // 是否禁用显隐
  order: 在 form 中的顺序， 有 order 的排序靠前， 数值越大， 越靠前
  暴露方法
  columnProps: 绑定给 el-table 的 column 中的其他选项
  resetTable 重置表格
  getTableList 刷新表格
 */

export default {
  components: {
    SearchFormItem,
    Screenfull,
    Pagination,
    Tree
  },
  props: {
    // api 必传
    requestApi: {
      type: Function,
      required: true
    },
    // 初始化请求参数 非必传, 这里的参数以后没一次请求都会携带
    initParam: {
      type: Object,
      default: () => {}
    },
    // 搜索部分的参数处理 非必传， 参数是当前搜索的字段
    searchHandler: {
      type: Function,
      default: () => false
    },
    // 对返回数据进行进一步处理 非必传 （包含分页）
    dataCallBack: {
      type: [Function, undefined],
      default: undefined
    },
    columns: {
      type: Array,
      default: () => []
    },
    // 是否需要全屏的按钮
    columnsScreenfull: {
      type: Boolean,
      default: true
    },
    // 重置按钮时候会触发的钩子
    resetHandler: {
      type: Function,
      default: () => {}
    },
    // 需要透传给 table 组件的属性
    tableProps: {
      type: Object,
      default: () => {}
    },
    // 是否需要分页
    pagination: {
      type: Boolean,
      default: true
    },
    // 是否需要参数携带 id 列表 （业务配置）
    requestBool: {
      type: Boolean,
      default: () => false
    },
    // 是否展示表格和 搜索之间的间隙
    tableSpaceCss: {
      type: Boolean,
      default: false
    },
    // 是否展示列设置
    columnsSetting: {
      type: Boolean,
      default: true
    },
    // 是否展示表格上方功能这一栏
    colSetting: {
      type: Boolean,
      default: true
    },
    // 需要选中的项， 非必传
    setSelectList: {
      type: Array,
      default: () => []
    },
    // 用户主动勾选触发
    initiativeSelect: {
      type: Function,
      default: () => {}
    },
    // 基于 tabs ， 动态监视不同 tabs 下 form 的高度
    tabs: {
      type: String,
      default: '1'
    },
    // 保存选中项的 key 默认是 id
    selectKey: {
      type: String,
      default: 'id'
    },
    activeName: {
      type: String,
      default: '1'
    }
  },
  data() {
    return {
      submitLoading: false,
      resetLoading: false,
      // 表格key
      tableKey: 1,
      // 列设置组件key
      treeKey: 1,
      // 传输给父组件的各类状态
      selectList: [],
      // 表格数据
      tableData: [],
      // 表单搜索部分通过 order 可排序
      formColumns: [],
      // 选中表格的行
      currentData: {},
      // 列设置中 tree配置
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      tableHeight: 506, // 表格高度
      commonHeight: 64, // 表单高度
      innerHeight: document.documentElement.clientHeight, // 页面高度
      screenfullStatus: false, // 全屏状态
      defaultCheckedKeys: [], // 列设置默认选中的节点
      checkedAll: [], // 全选时的 key
      checkedNull: [], // 全不选时的 key
      showMoreButton: false,
      searchParam: {}, // 搜索项参数
      resetSearchParams: {}, // 需要过滤以后得搜索项参数
      isMore: false, // 是否是展示更多的 状态
      tableLoading: false, // 表格 loading
      tableTop: 200, // 表格顶部距离页面高度
      renderColoums: [],
      dayjs,
      pageShow: true, // 是否展示分页， 由子组件控制的
      pageable: {
        // 当前页数
        pageNum: 1,
        // 每页显示条数
        pageSize: 10,
        // 总条数
        total: 0
      }
    }
  },
  computed: {
    // 动态计算表单区域 + 操作栏区域 + 分页部分高度
    mergeHeight() {
      // 带间距 全屏幕下使用的时候
      if (this.tableSpaceCss) {
        // this.tableKey++
        this.getTableTopDistance()
        return this.innerHeight - this.tableTop
      }
      if (this.isScreenfull) {
        this.getTableTopDistance()
        return this.innerHeight - this.tableTop
      } else {
        return 506
      }
    }
  },
  watch: {
    activeName() {
      // 切换标签页的时候需要从新计算的值
      this.toShowMore()
      // 全屏的情况下才启用， 不然在地图下面会触发滚动条的滚动
      if (this.isScreenfull) {
        this.getTableTopDistance()
      }
    },
    isMore() {
    }
  },
  created() {
    // 初始化选中项列表、存储选中项数据、侦听 展开按钮事件
    this.columnsHanlder()
    this.checkedAll = ['all', ...this.columns.map((item) => item.prop)]
    this.checkedNull = this.columns.filter((item) => item.disabled).map((item) => item.prop)
    this.defaultCheckedKeys = this.checkedAll
    this.toShowMore()
    window.addEventListener(
      'resize',
      () => {
        this.toShowMore()
        this.HeightChange()
      },
      false
    )
    // 如果是地图触发的更新， 不需要组组初始化调用请求， 由父组件调用
    if (this.requestBool) return
    this.getTableList()
  },
  // 解决 自定义列 + 固定列 导致显示问题  参考 https://blog.csdn.net/qq_36126031/article/details/121970398
  updated() {
    this.$refs.table.doLayout()
  },
  mounted() {
    this.init()
  },
  methods: {
    // 后端排序预留  table 属性  @sort-change="sortChange"  ， column 属性  :sortable="!item.sortable ? 'custom' : false"
    sortChange(change) {
      console.log('change', change)
      this.getTableList()
    },
    // 在全屏情况下， 分页切换， 和展开收起切换， 需要从新计算表格高度
    refreshTableHeigh() {
      if (this.isScreenfull) {
        this.getTableTopDistance()
        // setTimeout(()=>{
        //   this.getTableTopDistance()
        // })
      }
    },
    getTableTopDistance() {
      // 计算表格最大高度， 减去表格上边框到顶部的距离， 加上分页的高度 及分页上下边距
      if (this.$refs.table) {
        const pageElement = this.$refs.pageRef?.$el
        let addHeigh = 60
        if (pageElement) {
          addHeigh = 0
          addHeigh += pageElement.offsetHeight
          const style = window.getComputedStyle(pageElement)
          addHeigh += (parseInt(style.marginTop, 10) * 3) + 5
        }
        this.tableTop = this.$refs.table.$el.getBoundingClientRect().top + addHeigh
      }
    },
    resetSelectHandler() {
      this.$refs.table?.clearSelection()
      // setTimeout(()=>{
        this.setSelectList?.forEach((item) => {
          if (this.tableData?.find((it) => it[this.selectKey] === item)) {
            this.$refs.table?.toggleRowSelection(
              this.tableData.find((it) => it[this.selectKey] === item),
              true
            )
          }
        })
      // },1)
    },
    screenfullChange(bool) {
      this.screenfullStatus = bool
    },
    HeightChange() {
      this.innerHeight = document.documentElement.clientHeight
    },
    onMouseOver(refName) {
      const parentWidth = this.$refs[refName][0].parentNode.offsetWidth
      const contentWidth = this.$refs[refName][0].offsetWidth
      // 判断是否开启tooltip功能
      if (contentWidth > parentWidth) {
        this.isShowTooltip = false
      } else {
        this.isShowTooltip = true
      }
    },
    // 处理 列设置的 columns 去掉 多选和 操作部分 ， 把 多选和操作部分的 disabled 赋值
    columnsHanlder() {
      this.renderColoums = this.columns.filter((item) => {
        if (item?.hide) {
          item.show = false
        }
        if (item.prop === 'selection' || item.prop === 'actions') {
          item.disabled = true
        }
        return item.prop !== 'selection' && item.prop !== 'actions' && !item?.hide
      })
      this.renderColoums.unshift({
        label: '全选',
        prop: 'all',
        draggable: false,
        show: true
      })
    },
    // 获取表格数据， params 为搜索部分参数，如果有， 则不使用 初始化参数, val 为 不在搜索项中的其他参数 ， bool 为是否从新选中
    async getTableList(val, bool) {
      // console.log('表格请求', val, bool, this.setSelectList);
      // 初始化参数 和分页信息
      this.tableLoading = true
      const other = val || {} // val 这里暂时只考虑 idlist 列表， 由于带了 id 列表后端还是分页给， 所以 pageSize 要放到最大， 不然分页的时候无法分离两种交互逻辑 requestBool
      const useParams = Object.assign(
        other,
        this.resetSearchParams,
        this.initParam,
        this.pagination
          ? {
            pageNum: this.pageable.pageNum,
            pageSize: this.pageable.pageSize
          }
          : {}
      )
      let { data } = await this.requestApi(useParams)
      this.dataCallBack && (data = this.dataCallBack(data))
      this.pagination && (this.pageable.total = data?.total)
      this.tableData = data?.list || []
      // 查询的时候 可以重新选中, 需要配合重置，重置需要清空选中列表。
      if (bool) {
        this.tableKey++
        this.$nextTick(() => {
          this.resetSelectHandler()
        })
      }
      this.submitLoading = false
      this.resetLoading = false
      this.tableLoading = false
    },
    // 列设置选中事件
    currentChange(e, d) {
      const { prop } = e
      if (prop === 'all') {
        this.columns.forEach((item) => {
          if (item.disabled) return
          if (item.hide) {
            item.show = false
          } else {
            item.show = d
          }
        })
        this.treeKey++
        if (d) {
          this.defaultCheckedKeys = this.checkedAll
        } else {
          this.defaultCheckedKeys = this.checkedNull
        }
        return
      }
      const obj = this.columns.find((it) => it.prop === e.prop)
      if (obj.hide) {
        obj.show = false
      } else {
        obj.show = d
      }
    },
    // form 根据 order 排序
    sortArrayByOrder(arr) {
      return arr.sort((a, b) => {
        // 如果a有order而b没有，返回-1（a排在前面）
        if (a.order && b.order === undefined) return -1
        // 如果b有order而a没有，返回1（b排在前面）
        if (b.order && a.order === undefined) return 1
        // 如果都没有order或者order相等，返回0（保持原来的顺序）
        if (a.order === b.order) return 0
        // 按照order从大到小排序
        return b.order - a.order
      })
    },
    renderFormColumns() {
      const crrent = this.columns.filter(item => item.search)
      this.formColumns = this.sortArrayByOrder(crrent)
    },
    // 预留
    init() {
      // 搜索部分的顺序重置
      this.renderFormColumns()
      // 判断本地是否有表格配置数据 ？ 加载 :  忽略
      // 获取表格数据
      // 重设表格高度
      this.$nextTick(() => {
        this.getTableTopDistance()
        window.addEventListener('resize', this.getTableTopDistance)
        const current = document.getElementById(`Common${this.tabs}`)
        if (!current) return
        const observer = new ResizeObserver((entries) => {
          const { height } = entries[0].contentRect
          this.commonHeight = height
          this.refreshTableHeigh()
        })
        // 使用观察器侦听表单高度变化
        observer.observe(current)
      })
    },
    // 重置查询项
    resetSearchParam() {
      this.searchParam = {} // 重置参数
      this.resetSearchParams = {} // 重置过滤后的搜索参数
    },
    resetTable() {
      this.defaultCheckedKeys = this.checkedAll // 重置列设置
      this.resetHandler() // 父组件钩子
      this.$refs?.childrenTree?.resetTree() // 子组件钩子
      this.$refs.table.clearSelection() // 清空选中项
      this.pageable.pageNum = 1 // 重置页码
      this.resetSearchParams = {} // 重置过滤后的搜索参数
      this.searchParam = {} // 重置参数
      this.renderColoums.map((item) => { // 重置 列设置的显示状态
        item.show = true
      })
      this.tableKey++
      this.getTableList() // 从新请求
      // ... 忽略
    },
    // 显示隐藏切换 && 保存表格配置
    saveTableColumns() {
      // setStorage 封装了 localStorage
      // setStorage('clueTable', this.columns)
    },
    // 选中表格行
    handelTableClick(row) {
      this.currentData = row
    },
    // table多选操作 不论用户选择 还是父组件触发重置选择的列表 都会触发
    handleSelectionChange(val) {
      this.selectList = val
    },
    // 用户勾选行才触发
    handleInitiativeSelect(val) {
      this.initiativeSelect(val)
    },
    // 用户勾选全选才触发
    handleInitiativeAllSelect(val) {
      this.initiativeSelect(val)
    },
    // 表头拖动事件
    surverWidth(newWidth, oldWidth, column, event) {
      this.columns = this.columns.map((v) => {
        if (v.prop === column.property) v.width = newWidth
        return v
      })
      this.saveTableColumns()
    },
    onSubmit(type) {
      switch (type) {
        case 'search':
          this.submitLoading = true
          this.pageable.pageNum = 1
          this.resetSearchParams = this.searchHandler(this.searchParam)
            ? this.searchHandler(this.searchParam)
            : this.searchParam
          this.getTableList(undefined, true)
          break
        case 'reset':
          this.resetLoading = true
          this.resetTable()
          break
      }
    },
    // 展开收起按钮 页面初始化时候调用，以及窗口size调整 以及侧边菜单变化时调用
    toShowMore() {
      this.$nextTick(() => {
        if (!this.$refs[`FormRef${this.tabs}`]) return
        const form = this.$refs[`FormRef${this.tabs}`].$el
        const formItems = form.querySelectorAll('.el-form-item')
        let previousItemTop = 0 // 用来记录上一个表单项的顶部位置
        let flag = false // 是否换行了
        // 遍历表单项检查它们的顶部位置
        for (let i = 0; i < formItems.length; i++) {
          const item = formItems[i]
          if (i === 0) {
            // 记录第一个表单项的顶部位置
            previousItemTop = item.offsetTop
          } else {
            // 如果当前表单项的顶部位置与上一个不同，表明发生了换行
            if (item.offsetTop !== previousItemTop) flag = true
          }
        }
        this.showMoreButton = flag
      })
    },
    // 如果传了枚举值，渲染的时候根据枚举值 区数据中的数据进行 枚举值映射，使用 逗号隔开。
    renderEnum(scope, item) {
      const current = scope.row[item.prop]
      if (current === 'NULL') {
        return null
      }
      // 没有 enum 则不需要映射, 没有值 返回原值
      if (!item?.enum || current === undefined || current === null) {
        return current
      }
      // 如果不是数组，直接拿取映射
      if (!Array.isArray(current)) {
        return item.enum.find((o) => o.value === current)?.label
      }
      // 如果数组长度是 0， 返回 undefined ，以免后面渲染  '[]'
      if (current?.length === 0) {
        return undefined
      }
      return current.map((it) => item.enum.find((o) => o.value === it).label).join(',')
    },
    // 分页部分
    handleSizeChange(val) {
      this.pageable.pageNum = 1
      this.pageable.pageSize = val
      this.handlerPagenation()
    },
    handleCurrentChange(val) {
      this.pageable.pageNum = val
      this.handlerPagenation()
    },
    handlerPagenation() {
      // 是否需要根据id查询
      if (this.requestBool) {
        this.getTableList({ idList: this.setSelectList }, true)
      } else {
        this.getTableList(undefined, true)
      }
    }
  }
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>
